세그멘테이션 오류
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
세그멘테이션 오류는 프로그램이 메모리에 부적절하게 접근하려 할 때 발생하는 런타임 오류로, 주로 프로그래밍 오류로 인해 발생한다. 널 포인터 역참조, 잘못된 메모리 접근, 버퍼 오버플로우, 스택 오버플로우, 댕글링 포인터, 와일드 포인터 등이 흔한 원인이며, 읽기 전용 메모리에 쓰기를 시도하거나 존재하지 않는 메모리 주소에 접근하는 경우에도 발생한다. 세그멘테이션 오류 발생 시 운영체제는 해당 프로세스를 종료시키며, 디버깅을 위해 코어 파일을 생성하기도 한다. 일부 시스템에서는 오류를 자체적으로 처리할 수도 있으며, 디버거, 코어 덤프 분석, 정적 분석 도구, 메모리 오류 검사 도구 등을 활용하여 디버깅할 수 있다.
더 읽어볼만한 페이지
세그멘테이션 오류 | |
---|---|
일반 정보 | |
현상 | 컴퓨터 시스템 오류 |
유형 | 오류 |
관련 | 메모리 관리, 포인터, C, C++, Rust, Objective-C, Pascal |
원인 | |
일반적인 원인 | 유효하지 않은 메모리 주소 접근 접근 권한이 없는 메모리 영역 접근 (예: 읽기 전용 영역에 쓰기) 스택 오버플로 |
구체적인 원인 | 널 포인터 역참조 해제된 메모리 접근 (댕글링 포인터) 배열 경계 초과 읽기 전용 메모리 영역에 쓰기 실행 불가능한 메모리 영역에서 코드 실행 |
결과 | |
결과 | 프로그램 강제 종료 |
추가 결과 | 데이터 손실 또는 시스템 불안정 초래 가능 |
해결 | |
해결 방법 | 코드 검토 및 디버깅 메모리 관리 오류 수정 유효성 검사 추가 (예: 포인터 유효성, 배열 인덱스 범위) 디버거 활용 |
방지 | 안전한 프로그래밍 언어 사용 (예: Rust) 정적 분석 도구 활용 코드 리뷰 강화 |
기타 | |
다른 이름 | 세그폴트, 액세스 위반, 보호 오류 |
2. 원인
세그멘테이션 오류는 프로그램이 접근 권한이 없거나 허용되지 않은 방식으로 메모리에 접근할 때 발생한다. 예를 들어, 읽기 전용 위치에 쓰기를 시도하거나 운영 체제의 일부를 덮어쓰려는 경우가 있다.[6]
"세그멘테이션"은 컴퓨팅에서 다양하게 사용되는데, "세그멘테이션 오류"는 ''프로그램''의 주소 공간을 가리킨다. 메모리 보호 기능이 있으면 프로그램 자체 주소 공간만 읽을 수 있으며, 이 중 스택과 읽기/쓰기 부분인 데이터 세그먼트만 쓰기가 가능하다. const 세그먼트에 할당된 읽기 전용 데이터와 코드 세그먼트는 쓰기가 불가능하므로, 프로그램 주소 공간 외부를 읽거나 읽기 전용 세그먼트에 쓰기를 시도하면 세그멘테이션 오류가 발생한다.[6]
가상 메모리를 제공하기 위해 하드웨어 메모리 세그멘테이션을 사용하는 시스템에서는, 하드웨어가 존재하지 않는 세그먼트를 참조하려는 시도, 세그먼트 범위를 벗어난 위치 참조, 또는 권한으로 허용되지 않은 방식으로 위치를 참조하려는 시도를 감지할 때 세그멘테이션 오류가 발생한다. 페이징만 사용하는 시스템에서는 잘못된 페이지 오류가 일반적으로 세그멘테이션 오류로 이어지며, 이들은 모두 가상 메모리 관리 시스템에서 발생시키는 오류이다. 유효한 페이지에 대한 불법적인 접근은 세그멘테이션 오류이지만 잘못된 페이지 오류는 아니며, 버퍼 오버플로우처럼 페이지 중간에서 세그멘테이션 오류가 발생할 수 있다.
하드웨어 수준에서 오류는 메모리 보호 기능의 일부로, 불법적인 접근(참조된 메모리가 존재하는 경우)에 대해 메모리 관리 장치(MMU)에 의해 처음 발생하거나 잘못된 페이지 오류(참조된 메모리가 존재하지 않는 경우)에 의해 발생한다. 잘못된 물리 주소인 경우 버스 오류가 대신 발생하지만, 항상 구분되는 것은 아니다.
운영 체제 수준에서 이 오류는 포착되어 해당 신호에 대한 프로세스의 처리기를 활성화하여 오류가 발생한 프로세스에 신호가 전달된다. 유닉스 계열 운영 체제에서는 SIGSEGV(''세그멘테이션 위반''의 약어) 신호가, 마이크로소프트 윈도우에서는 STATUS_ACCESS_VIOLATION 예외가 오류 발생 프로세스로 전송된다.
세그멘테이션 오류 발생 조건과 현상은 하드웨어 및 운영 체제에 따라 다르다.[6] 근본 원인은 메모리 접근 위반이지만, 일반적으로 소프트웨어 버그이다. 근본 원인 분석 – 버그 디버깅은 프로그램이 일관되게 세그멘테이션 오류를 발생시키는 경우(예: 널 포인터 역참조)에는 간단할 수 있지만, 다른 경우에는 버그를 재현하기 어렵고 각 실행 시 메모리 할당에 따라 달라질 수 있다(예: 댕글링 포인터 역참조).
일반적인 원인은 다음과 같다.
- 존재하지 않는 메모리 주소 접근 (프로세스 주소 공간 외부)
- 권한 없는 메모리 접근 (프로세스 컨텍스트의 커널 구조체 등)
- 읽기 전용 메모리 (예: 코드 세그먼트)에 쓰기 시도
이러한 오류는 유효하지 않은 메모리 접근을 초래하는 프로그래밍 오류로 인해 발생한다. C 코드에서 세그멘테이션 오류는 포인터 사용 오류, 특히 C 동적 메모리 할당에서 많이 발생한다. 정의되지 않은 동작을 초래하는 널 포인터 역참조는 보통 세그멘테이션 오류를 발생시키는데, 널 포인터는 유효한 메모리 주소가 될 수 없기 때문이다. 반면 와일드 포인터와 댕글링 포인터는 존재 여부, 읽기/쓰기 가능 여부가 불확실한 메모리를 가리키므로 일시적인 버그를 초래할 수 있다.
2. 1. 흔한 원인
다음은 세그멘테이션 오류를 발생시키는 일반적인 원인과 그 예시다.- 존재하지 않는 메모리 주소 접근: 프로세스가 자신의 주소 공간 밖의 메모리에 접근하려는 경우이다.
- 권한 없는 메모리 접근: 프로세스가 권한이 없는 메모리 영역에 접근하려는 경우이다. (예: 커널 구조체)
- 읽기 전용 메모리에 쓰기: 코드 세그먼트와 같이 읽기 전용으로 설정된 메모리 영역에 쓰기를 시도하는 경우이다.
const char *s = "hello world";
- s = 'H'; // 읽기 전용 메모리 영역에 쓰기 시도
위 코드는 읽기 전용 문자열 리터럴 "hello world"를 수정하려 하기 때문에 세그멘테이션 오류를 발생시킨다.
이러한 오류들은 대부분 포인터 사용 오류, 특히 C 동적 메모리 할당과 관련된 오류로 인해 발생한다.
- 널 포인터 역참조: 널 포인터는 아무것도 가리키지 않는 포인터인데, 이 포인터를 통해 메모리에 접근(읽거나 쓰기)하면 대부분의 운영체제에서 세그멘테이션 오류가 발생한다.
int* ptr = (int*) 0x00000000; // 널 포인터
- ptr = 1; // 널 포인터 역참조
- 와일드 포인터 역참조: 초기화되지 않은 포인터는 임의의 메모리 주소를 가리키는 와일드 포인터가 되며, 이를 역참조하면 예측 불가능한 결과나 세그멘테이션 오류를 유발할 수 있다.
- 댕글링 포인터 역참조: 이미 해제된 메모리를 가리키는 댕글링 포인터를 역참조하는 경우에도 세그멘테이션 오류가 발생할 수 있다.
char *p2; // 와일드 포인터: 초기화되지 않음.
char *p3 = malloc(10 * sizeof(char)); // 메모리 할당
free(p3); // 메모리 해제, p3는 이제 댕글링 포인터
- 버퍼 오버플로우: 배열의 경계를 넘어선 메모리 접근은 주변 메모리 영역을 손상시켜 세그멘테이션 오류를 일으킬 수 있다.
char s[] = "hello world";
char c = s[20]; // 배열 범위를 벗어난 접근
- 스택 오버플로우: 함수 호출이 너무 많이 중첩되어 콜 스택이 가득 차면 스택 오버플로우가 발생하고, 이는 세그멘테이션 오류로 이어질 수 있다.
int main(void)
{
return main(); // 무한 재귀, 스택 오버플로우 유발
}
세그멘테이션 오류가 발생하는 조건과 그 현상은 하드웨어 및 운영 체제에 따라 다르다.[6] 유닉스 계열 운영 체제에서는 SIGSEGV 신호가, 마이크로소프트 윈도우에서는 STATUS_ACCESS_VIOLATION 예외가 발생한다.
2. 2. 구체적인 발생 조건
세그멘테이션 오류는 프로그램이 허용되지 않는 방식으로 메모리에 접근할 때 발생한다. 이는 주로 다음과 같은 상황에서 발생한다.[6]- 읽기 전용 메모리에 쓰기: 프로그램의 코드 세그먼트나 읽기 전용 데이터 세그먼트와 같이 쓰기가 금지된 메모리 영역에 쓰기 작업을 시도하면 세그멘테이션 오류가 발생한다. 예를 들어, 다음과 같은 C 코드는 읽기 전용 문자열 리터럴에 값을 쓰려고 시도하므로 세그멘테이션 오류를 발생시킨다.
```c
const char *s = "hello world";
- s = 'H';
```
이 코드를 컴파일하고 실행하면, 운영 체제는 문자열 "hello world"를 읽기 전용 메모리 영역에 배치한다. 따라서 `*s = 'H';` 문장은 읽기 전용 영역에 쓰기를 시도하는 것이 되어 세그멘테이션 오류가 발생한다.
- 존재하지 않는 메모리 주소 접근: 프로세스의 주소 공간 외부에 있는 메모리 주소에 접근을 시도하는 경우, 운영체제는 이를 감지하고 세그멘테이션 오류를 발생시킨다.
- 권한 없는 메모리 접근: 커널 영역의 메모리와 같이 일반 사용자 프로그램이 접근할 수 없는 메모리 영역에 접근을 시도하는 경우에도 세그멘테이션 오류가 발생한다.
- 잘못된 시스템 호출: 운영체제에 잘못된 시스템 호출을 요청하는 경우에도 세그멘테이션 오류가 발생할 수 있다.
널 포인터 역참조는 매우 흔한 오류인데, 대부분의 운영 체제는 메모리의 첫 페이지(주소 0에서 시작)를 비워두고 널 포인터 접근 시 세그멘테이션 오류가 발생하도록 한다. 다음 코드는 널 포인터에 값을 쓰려고 시도하므로 세그멘테이션 오류를 유발한다.
```c
int* ptr = (int*) 0x00000000;
- ptr = 1;
```
이 외에도, 버퍼 오버플로우, 스택 오버플로우, 초기화되지 않은 포인터 사용, 해제된 메모리 접근 등 다양한 프로그래밍 오류가 세그멘테이션 오류를 유발할 수 있다.
세그멘테이션 오류가 발생하는 구체적인 조건과 그 표현 방식은 운영 체제에 따라 다를 수 있다. 예를 들어, GNU/Linux에서 GCC로 위 C 코드를 컴파일하면 컴파일 오류가 발생하지만, OpenBSD에서는 런타임 오류(세그멘테이션 오류)가 발생한다.
3. 처리
세그멘테이션 오류가 발생하면, 운영체제는 일반적으로 해당 프로세스를 강제 종료한다.
- 신호 처리: 유닉스 계열 운영체제에서는 SIGSEGV (세그멘테이션 위반의 약어) 신호를 발생시켜 프로세스에 세그멘테이션 오류가 발생했음을 알린다.[6] 프로세스는 이 신호를 처리하는 핸들러를 등록하여 오류에 대응할 수 있다.
- 예외 처리: 마이크로소프트 윈도우에서는 STATUS_ACCESS_VIOLATION 예외를 발생시켜 세그멘테이션 오류를 처리한다.[6]
- 코어 덤프: 운영체제는 디버깅을 위해 코어 덤프 파일을 생성할 수 있다. 코어 덤프 파일에는 오류 발생 당시의 프로세스 메모리 상태가 저장되어 있어, 개발자가 오류의 원인을 분석하는 데 도움을 준다.
Linux 및 Windows와 같은 일부 시스템에서는 프로그램 자체에서 세그멘테이션 오류를 처리할 수 있다.[7] 아키텍처와 운영 체제에 따라 실행 중인 프로그램은 이벤트를 처리할 수 있을 뿐만 아니라 스택 트레이스, 프로세서 레지스터 값, 오류가 발생한 소스 코드 줄, 잘못 액세스된 메모리 주소[8], 그리고 작업이 읽기인지 쓰기인지와 같은 상태에 대한 일부 정보를 추출할 수 있다.[9]
일반적으로 세그멘테이션 오류는 프로그램에 수정이 필요한 버그가 있음을 의미하지만, 테스트, 디버깅, 메모리에 직접 액세스해야 하는 플랫폼을 에뮬레이션하기 위해 의도적으로 이러한 오류를 발생시키는 것도 가능하다. 후자의 경우, 시스템은 오류가 발생한 후에도 프로그램이 계속 실행되도록 허용해야 한다. 이 경우, 시스템에서 허용하면 이벤트를 처리하고 프로세서 프로그램 카운터를 증가시켜 오류가 발생한 명령을 "건너뛰어" 실행을 계속할 수 있다.[10]
읽기 전용 메모리에 쓰기는 세그멘테이션 오류를 발생시킨다. 코드 오류 수준에서 이는 프로그램이 자체 코드 세그먼트의 일부 또는 읽기 전용 데이터 세그먼트의 일부에 쓰기를 시도할 때 발생하며, 이는 운영 체제에 의해 읽기 전용 메모리에 로드된다.
다음은 메모리 보호 기능이 있는 플랫폼에서 일반적으로 세그멘테이션 오류를 일으키는 ANSI C 코드의 예이다. 이는 문자열 리터럴을 수정하려는 시도로, ANSI C 표준에 따르면 정의되지 않은 동작이다. 대부분의 컴파일러는 이를 컴파일 시간에 감지하지 않고 대신 충돌하는 실행 코드로 컴파일한다.
```c
int main(void)
{
char *s = "hello world";
- s = 'H';
}
4. 예제
다음은 메모리 보호 기능을 가진 플랫폼에서 세그멘테이션 오류를 발생시키는 ANSI C 언어 코드의 예시이다.
```c
const char *s = "hello world";
- s = 'H';
```
위 코드를 포함하는 프로그램이 컴파일될 때, "hello world" 문자열 리터럴은 읽기 전용으로 표시된 프로그램 바이너리의 섹션에 위치한다. 로드될 때, 운영 체제는 이를 읽기 전용 메모리 세그먼트에 다른 문자열 및 상수 데이터와 함께 배치한다. 실행될 때, 's' 변수는 문자열의 위치를 가리키도록 설정되고, 이 변수를 통해 'H' 문자를 메모리에 쓰려고 시도하면 세그멘테이션 오류가 발생한다.
이러한 프로그램을 컴파일하고 실행하면, 예를 들어 다음과 같은 런타임 오류가 발생한다.
```bash
$ gcc segfault.c -g -o segfault
$ ./segfault
Segmentation fault
```
다음은 GNU 디버거의 스택 트레이스이다.
```c
Program received signal SIGSEGV, Segmentation fault.
0x1c0005c2 in main () at segfault.c:6
6 *s = 'H';
```
한편, 리눅스 상의 GCC 4.1.1은 기본적으로 컴파일 시 오류를 발생시킨다.
```bash
$ gcc segfault.c -g -o segfault
segfault.c: In function ‘main’:
segfault.c:4: error: assignment of read-only location
```
세그멘테이션 오류가 발생하는 조건과 이를 사용자에게 알려주는 방법은 운영 체제에 따라 다르다.

매우 일반적인 프로그램 오류는 널 포인터의 역참조(널 포인터를 통한 읽기 또는 쓰기)이다. C 언어에서는 "존재하지 않는 객체에 대한 포인터"를 의미하며, 오류 지시자로 사용된다. 대부분의 운영체제는 접근 시 세그멘테이션 오류를 일으키는 주소를 널 포인터에 매핑한다.
4. 1. 널 포인터 역참조 예제
cint* ptr = (int*) 0x00000000;
- ptr = 1;
```
위 코드는 널 포인터 `ptr`이 가리키는 메모리 위치에 값을 쓰려고 시도하므로 세그멘테이션 오류가 발생한다.
```c
int *ptr = NULL;
printf("%d", *ptr);
```
이 코드는 널 포인터를 생성한 다음 해당 값을 읽으려고 시도한다. 이 동작은 많은 운영 체제에서 런타임에 세그멘테이션 오류를 발생시킨다.
```c
int *ptr = NULL;
- ptr = 1;
```
널 포인터를 역참조한 다음 값을 할당하는 것(존재하지 않는 대상에 값을 쓰는 것)도 일반적으로 세그멘테이션 오류를 발생시킨다.
```c
int *ptr = NULL;
- ptr;
```
위 코드는 널 포인터 역참조를 포함하지만, 값이 사용되지 않으므로 컴파일 시 세그멘테이션 오류가 발생하지 않는 경우가 많다. 따라서 역참조는 데드 코드 제거에 의해 최적화될 수 있다.
5. 디버깅
세그멘테이션 오류는 디버깅하기 어려운 문제 중 하나이며, 오류 원인을 파악하기 위해 다음과 같은 방법을 사용할 수 있다.
메모리 보호 기능을 사용하는 플랫폼에서 세그멘테이션 오류를 발생시키는 ANSI C 코드 예시는 다음과 같다.
```c
const char *s = "hello world";
- s = 'H';
```
위 코드를 포함하는 프로그램을 컴파일하면, "hello world" 문자열은 읽기 전용으로 표시된 프로그램의 섹션에 위치한다. 프로그램 로드 시, 운영 체제는 이 문자열과 상수 데이터를 메모리의 읽기 전용 세그먼트에 배치한다. 프로그램 실행 시, 변수 's'는 문자열의 위치를 가리키게 되고, 'H'라는 문자를 변수 s를 통해 메모리에 기록하려는 시도는 세그멘테이션 오류를 발생시킨다.
OpenBSD 4.0에서 이런 프로그램을 컴파일하고 실행하면 런타임 오류가 발생하고, GNU/Linux에서 GCC 4.1.1로 같은 시도를 하면 컴파일 오류가 발생한다. 이처럼 세그멘테이션 경고 발생 조건이나 사용자에게 알리는 방법은 운영 체제에 따라 다르다.
널 포인터 역참조는 흔히 발생하는 오류이므로, 대부분의 운영 체제는 메모리의 첫 페이지(주소 0에서 시작)를 살피며, 여기에 접근하면 세그멘테이션 오류가 발생한다.
```c
int* ptr = (int*) 0x00000000;
- ptr = 1;
```
위 코드는 메모리 주소 0x00000000에 접근하는 포인터를 생성하고, 그 곳에 값을 할당하려고 시도한다. 이러한 행동은 많은 컴파일러에서 세그멘테이션 오류를 유발한다.
5. 1. 디버거 사용
GDB(GNU 디버거)와 같은 디버거를 사용하면 프로그램 실행을 단계별로 추적하고, 오류 발생 지점의 메모리 상태를 확인할 수 있다. 다음은 세그멘테이션 오류가 발생한 코드에 대한 GDB 추적 결과 예시이다.Program received signal SIGSEGV, Segmentation fault.
0x1c0005c2 in main () at segfault.c:6
6 *s = 'H';
이 예시는 `segfault.c` 파일의 6번째 줄에서 `*s = 'H';` 코드 실행 중 세그멘테이션 오류(SIGSEGV)가 발생했음을 보여준다.
5. 2. 코어 덤프 분석
메모리 보호를 사용하는 플랫폼에서 세그멘테이션 오류를 발생시키는 ANSI C 코드 예시는 다음과 같다.const char *s = "hello world";
- s = 'H';
위 코드를 포함하는 프로그램을 컴파일하면, "hello world" 문자열은 프로그램에서 읽기 전용이 된다. 프로그램이 로드될 때, 운영 체제는 이 문자열과 상수 데이터를 메모리의 읽기 전용 세그먼트에 배치한다. 프로그램 실행 시, 변수 's'는 문자열의 위치를 가리키게 되고, 'H'라는 문자를 변수 s를 통해 메모리에 기록하려는 시도는 세그멘테이션 오류를 발생시킨다.
OpenBSD 4.0에서 이 프로그램을 컴파일하고 실행하면 다음과 같은 런타임 오류가 발생한다.
$ gcc segfault.c -g -o segfault
$ ./segfault
Segmentation fault
GDB(GNU 디버거)를 통한 추적 결과는 다음과 같다.
Program received signal SIGSEGV, Segmentation fault.
0x1c0005c2 in main () at segfault.c:6
6 *s = 'H';
반면, GNU/Linux에서 GCC 4.1.1로 같은 시도를 하면 컴파일 에러가 발생한다.
$ gcc segfault.c -g -o segfault
segfault.c: In function ‘main’:
segfault.c:4: error: assignment of read-only location
세그멘테이션 경고 발생 조건이나 사용자에게 알려주는 방법은 운영 체제에 따라 다르다.
널 포인터 역참조(주소 '0'을 참조하는 널 포인터를 통한 읽기나 쓰기로, C에서 '아무것도 가리키지 않는 포인터'를 나타내기 위해 또는 오류 지시자로 사용)는 흔히 발생하는 오류이다. 대부분의 운영 체제는 메모리의 첫 페이지(주소 0에서 시작)를 살피며, 따라서 여기에 접근하면 세그멘테이션 오류가 발생한다.
int* ptr = (int*) 0x00000000;
- ptr = 1;
위 코드는 메모리 주소 0x00000000에 접근하는 포인터를 생성하고, 그 곳에 값을 할당하려고 시도한다. 이러한 행동은 많은 컴파일러에서 세그멘테이션 오류를 유발한다.
5. 3. 정적 분석 도구
정적 분석 도구는 코드를 실행하지 않고도 잠재적인 오류를 찾아낼 수 있다. 예를 들어, GNU/Linux에서 GCC 4.1.1로 다음과 같은 코드를 컴파일하면:const char *s = "hello world";
- s = 'H';
컴파일 시점에 다음과 같은 오류가 발생한다.
$ gcc segfault.c -g -o segfault
segfault.c: In function ‘main’:
segfault.c:4: error: assignment of read-only location
이는 문자열 "hello world"가 읽기 전용 메모리 영역에 할당되기 때문에 발생하는 오류이다. 반면, 같은 코드를 OpenBSD 4.0에서 컴파일하면 컴파일 시점에는 오류가 발생하지 않지만, 실행 시점에 세그멘테이션 오류가 발생한다.
또 다른 예로, 다음과 같이 널 포인터를 역참조하는 코드는:
int* ptr = (int*) 0x00000000;
- ptr = 1;
많은 컴파일러에서 세그멘테이션 오류를 발생시킨다. 이는 널 포인터(주소 '0'을 참조하는 포인터)를 통해 메모리에 접근하려 하기 때문이다.
5. 4. 메모리 오류 검사 도구
메모리 보호 기능을 사용하는 플랫폼에서 세그멘테이션 오류를 발생시키는 ANSI C 코드 예시는 다음과 같다.```c
const char *s = "hello world";
- s = 'H';
```
위 코드를 포함하는 프로그램이 컴파일되면, "hello world" 문자열은 읽기 전용으로 표시된 프로그램의 섹션에 위치한다. 프로그램이 로드될 때, 운영 체제는 이 문자열과 상수 데이터를 메모리의 읽기 전용 세그먼트에 배치한다. 프로그램 실행 시, 변수 's'는 문자열의 위치를 가리키게 되고, 'H'라는 문자를 변수 s를 통해 메모리에 기록하려는 시도는 세그멘테이션 오류를 발생시킨다.
OpenBSD 4.0에서 이런 프로그램을 컴파일하고 실행하면 다음과 같은 런타임 오류가 발생한다.
```bash
$ gcc segfault.c -g -o segfault
$ ./segfault
Segmentation fault
```
GDB(GNU 디버거)를 통한 추적 결과는 다음과 같다.
```c
Program received signal SIGSEGV, Segmentation fault.
0x1c0005c2 in main () at segfault.c:6
6 *s = 'H';
```
반면, 리눅스에서 GCC 4.1.1로 같은 시도를 하면 컴파일 오류가 발생한다.
```bash
$ gcc segfault.c -g -o segfault
segfault.c: In function ‘main’:
segfault.c:4: error: assignment of read-only location
```
즉, 세그멘테이션 경고가 발생하는 조건이나 사용자에게 알리는 방법은 운영 체제에 따라 다르다.
널 포인터 역참조(주소 '0'을 참조하는 널 포인터를 통한 읽기나 쓰기로, C에서 '아무것도 가리키지 않는 포인터'를 나타내기 위해 또는 오류 지시자로 사용)는 흔히 발생하는 오류이므로, 대부분의 운영 체제는 메모리의 첫 페이지(주소 0에서 시작)를 살피며, 여기에 접근하면 세그멘테이션 오류가 발생한다.
```c
int* ptr = (int*) 0x00000000;
- ptr = 1;
```
위 코드는 메모리 주소 0x00000000에 접근하는 포인터를 생성하고, 그 곳에 값을 할당하려고 시도한다. 이러한 행동은 많은 컴파일러에서 세그멘테이션 오류를 일으킨다.
6. 기타
세그멘테이션 오류는 프로그램이 접근 권한이 없거나 허용되지 않은 방식으로 메모리에 접근할 때 발생한다. 이는 운영체제의 메모리 보호 기능과 관련이 깊다.
"세그멘테이션"은 컴퓨팅에서 여러 의미로 쓰이지만, 여기서는 프로그램의 주소 공간을 뜻한다.[6] 메모리 보호 기능이 있는 시스템에서는 프로그램 자체 주소 공간만 읽을 수 있고, 그중에서도 쓰기가 가능한 부분은 스택과 데이터 세그먼트(읽기/쓰기 가능)로 제한된다. 코드 세그먼트나 읽기 전용 데이터에는 쓸 수 없다.
하드웨어 메모리 세그멘테이션을 사용하는 시스템에서는 세그멘테이션 오류가 존재하지 않는 세그먼트나 범위를 벗어난 위치를 참조할 때, 또는 권한에 맞지 않는 방식으로 접근할 때 발생한다. 페이징만 쓰는 시스템에서는 보통 잘못된 페이지 오류가 세그멘테이션 오류로 이어진다. 이 둘은 모두 가상 메모리 관리 시스템에서 발생하는 오류다. 하지만 페이지 오류 없이 세그멘테이션 오류가 발생할 수도 있는데, 예를 들어 버퍼 오버플로우처럼 유효한 페이지 내에서 잘못된 메모리 덮어쓰기가 일어나는 경우다.
하드웨어 수준에서는 메모리 관리 장치(MMU)가 불법적인 접근을 감지하거나, 참조된 메모리가 없을 때 잘못된 페이지 오류를 발생시킨다. 잘못된 물리 주소가 문제라면 버스 오류가 발생할 수도 있지만, 항상 구별되는 것은 아니다.
운영 체제는 이 오류를 포착해 프로세스에 신호를 전달한다. 유닉스 계열 운영 체제는 SIGSEGV(세그멘테이션 위반) 신호를, 마이크로소프트 윈도우는 STATUS_ACCESS_VIOLATION 예외를 발생시킨다.
6. 1. 운영체제별 처리
메모리 보호를 사용하는 플랫폼에서 세그멘테이션 오류를 발생시키는 ANSI C 코드의 예시는 다음과 같다.[1]```c
const char *s = "hello world";
- s = 'H';
```
위 코드를 포함하는 프로그램이 컴파일되면, "hello world" 문자열은 프로그램에서 읽기 전용이 된다.[1] 프로그램이 로드되었을 때, 운영 체제는 이 문자열과 상수 데이터를 메모리의 읽기 전용 세그먼트에 배치한다.[1] 프로그램이 실행되면, 변수 's'는 이 문자열의 위치를 가리키게 되고, 'H'라는 문자를 변수 s를 통해 메모리에 기록하려는 시도는 곧 세그멘테이션 오류를 일으키게 된다.[1]
OpenBSD 4.0에서 이런 프로그램을 컴파일하고 실행하면 다음과 같은 런타임 오류가 발생한다.[1]
```bash
$ gcc segfault.c -g -o segfault
$ ./segfault
Segmentation fault
```
GDB를 통한 추적 결과는 다음과 같다.[1]
```c
Program received signal SIGSEGV, Segmentation fault.
0x1c0005c2 in main () at segfault.c:6
6 *s = 'H';
```
반면, GNU/Linux에서 GCC 4.1.1로 같은 시도를 하면 컴파일 에러가 발생한다.[1]
```bash
$ gcc segfault.c -g -o segfault
segfault.c: In function ‘main’:
segfault.c:4: error: assignment of read-only location
```
즉, 세그멘테이션 경고가 발생하는 조건이나 그것을 사용자에게 알려주는 방법은 운영 체제에 따라서도 다르다.[1]
널 포인터 역참조(주소 '0'을 참조하는 포인터인 널 포인터를 통한 읽기나 쓰기로, C에서 '아무것도 가리키지 않는 포인터'를 나타내기 위해서 또는 오류 지시자로 사용)는 흔히 일어나는 오류이기 때문에, 대부분의 운영 체제는 메모리의 첫 페이지(주소 0에서 시작하는)를 살피며, 따라서 여기에 접근하면 세그멘테이션 오류가 발생한다.[1]
```c
int* ptr = (int*) 0x00000000;
- ptr = 1;
```
위 샘플 코드는 메모리 주소 0x00000000에 접근하는 포인터를 생성하고, 그 곳에 값을 할당하려고 시도한다. 이런 행동은 많은 컴파일러에서 세그멘테이션 오류를 일으킨다.[1]
6. 2. 하드웨어와의 관계
세그멘테이션 오류는 프로그램이 접근 권한이 없는 메모리 위치에 접근하려 하거나, 허용되지 않은 방식으로 메모리 위치에 접근할 때 발생한다. 예를 들어, 읽기 전용 위치에 쓰기를 시도하거나 운영 체제의 일부를 덮어쓰려는 경우가 이에 해당한다.[6]"세그멘테이션"이라는 용어는 ''프로그램''의 주소 공간을 의미한다.[6] 메모리 보호를 사용하면 프로그램 자체의 주소 공간만 읽을 수 있으며, 이 중 스택과 프로그램의 읽기/쓰기 부분인 데이터 세그먼트만 쓰기가 가능하다. 코드 세그먼트와 const 세그먼트에 할당된 읽기 전용 데이터는 쓰기가 불가능하다. 따라서 프로그램 주소 공간 외부를 읽거나 읽기 전용 세그먼트에 쓰기를 시도하면 세그멘테이션 오류가 발생한다.
가상 메모리를 제공하기 위해 하드웨어 메모리 세그멘테이션을 사용하는 시스템에서, 세그멘테이션 오류는 하드웨어가 존재하지 않는 세그먼트를 참조하려는 시도, 세그먼트 범위를 벗어난 위치 참조, 또는 권한으로 허용되지 않은 방식으로 위치를 참조하려는 시도를 감지할 때 발생한다. 페이징만 사용하는 시스템에서는 잘못된 페이지 오류가 일반적으로 세그멘테이션 오류로 이어진다. 세그멘테이션 오류와 페이지 오류는 모두 가상 메모리 관리 시스템에서 발생시키는 오류이다. 세그멘테이션 오류는 페이지 오류와 독립적으로 발생할 수도 있는데, 유효한 페이지에 대한 불법적인 접근은 세그멘테이션 오류이지만 잘못된 페이지 오류는 아니다. 예를 들어, 페이지 내에 머무르면서 불법적으로 메모리를 덮어쓰는 버퍼 오버플로우와 같은 경우 페이지 중간에서 세그멘테이션 오류가 발생할 수 있다.
하드웨어 수준에서 오류는 메모리 보호 기능의 일부로, 불법적인 접근(참조된 메모리가 존재하는 경우)에 대해 메모리 관리 장치(MMU)에 의해 처음 발생하거나 잘못된 페이지 오류(참조된 메모리가 존재하지 않는 경우)에 의해 발생한다. 문제가 잘못된 논리 주소가 아닌 잘못된 물리 주소인 경우, 버스 오류가 대신 발생하지만, 항상 구분되는 것은 아니다.
운영 체제 수준에서 이 오류는 포착되어 해당 신호에 대한 프로세스의 처리기를 활성화하여 오류가 발생한 프로세스에 신호가 전달된다. 유닉스 계열 운영 체제에서는 SIGSEGV(''세그멘테이션 위반''에서 약어)라는 신호가 오류가 발생한 프로세스로 전송된다. 마이크로소프트 윈도우에서 오류가 발생한 프로세스는 STATUS_ACCESS_VIOLATION 예외를 수신한다.
7. 대한민국 관련 정보
(이전 답변에서 원본 소스가 제공되지 않아 내용을 생성할 수 없었습니다. 따라서 수정할 내용도 없습니다. 원본 소스가 제공되면 지침에 따라 수정하고 출력하겠습니다.)
참조
[1]
서적
Expert C programming: deep C secrets
[2]
웹사이트
The Rust Programming Language - Ownership
https://doc.rust-lan[...]
[3]
웹사이트
Fearless Concurrency with Rust - The Rust Programming Language Blog
http://blog.rust-lan[...]
[4]
간행물
Recursive functions of symbolic expressions and their computation by machine, Part I
http://www-formal.st[...]
2018-09-22
[5]
간행물
Memory safety without runtime checks or garbage collection
http://llvm.org/pubs[...]
ACM
2018-09-22
[6]
웹사이트
Debugging Segmentation Faults and Pointer Problems - Cprogramming.com
https://www.cprogram[...]
2021-02-03
[7]
웹사이트
Cleanly recovering from Segfaults under Windows and Linux (32-bit, x86)
https://feepingcreat[...]
2020-08-23
[8]
웹사이트
Implementation of the SIGSEGV/SIGABRT handler which prints the debug stack trace.
https://github.com/v[...]
2020-08-23
[9]
웹사이트
How to identify read or write operations of page fault when using sigaction handler on SIGSEGV?(LINUX)
https://stackoverflo[...]
2020-08-23
[10]
웹사이트
LINUX – WRITING FAULT HANDLERS
https://devarea.com/[...]
2020-08-23
[11]
서적
ISO/IEC 9899:1990 - Programming languages -- C
[12]
서적
ISO/IEC 9899:1999 - Programming languages -- C
[13]
서적
ISO/IEC 9899:2011 - Programming languages -- C
http://www.iso-9899.[...]
[14]
웹사이트
What is the difference between a segmentation fault and a stack overflow?
https://stackoverflo[...]
2023-11-11
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com